package com.espirit.eap.manager;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;

import javax.annotation.Resource;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.springframework.stereotype.Service;

import com.espirit.common.VersionAware;
import com.espirit.eap.ICheckModelDuplicateInfo;
import com.espirit.eap.ICheckModelNotNullInfo;
import com.espirit.eap.PinyinAware;
import com.espirit.eap.RevisionHistoryAware;
import com.espirit.eap.ValidationUtil;
import com.espirit.eap.sa.EmployeeAware;
import com.espirit.eap.sa.LoginUser;
import com.espirit.eap.sa.LoginUserService;
import com.espirit.eap.sa.User;
import com.espirit.eap.util.ChineseSpeller;
import com.espirit.finance.core.AcctTerm;
import com.espirit.finance.core.AcctTermCheckAware;
import com.googlecode.cswish.exception.ApplicationException;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.ObjectFactory;
import com.googlecode.cswish.util.ClassUtil;

@Service
public class DefaultEntityInterceptor extends EmptyInterceptor {
	
	private static final long serialVersionUID = -5806478602123863531L;

	@Resource
	private ValidationUtil genericServiceUtil;
	
	private LoginUserService loginUserService;
	
	private SystemLogService systemLogService;
	
	BeanIntrospector beanIntrospector;
	
	private ProofNbrRuleManager proofNbrRuleManager;
	
	public boolean onSave(Object entity, Serializable id, Object[] state,
			String[] propertyNames, Type[] types) {
		boolean modified = false;
		
		if (entity instanceof RevisionHistoryAware){
			if (id == null){
				LoginUserService userService = getUserService();
				RevisionHistory revisionHistory = ((RevisionHistoryAware)entity).safeRevisionHistory();
				LoginUser loginUser = userService.getLoginUser();
				if (revisionHistory.getModifyOn() == null){
					revisionHistory.setModifyOn(new Date());
					revisionHistory.setCreatedOn(new Date());
				} else {
					Calendar right = Calendar.getInstance();
					right.setTime(revisionHistory.getModifyOn());
					if (right.get(Calendar.YEAR) == 1900){
						revisionHistory.setModifyOn(null);
					} else {
						revisionHistory.setCreatedOn(revisionHistory.getModifyOn());
					}
				}
				
				if (revisionHistory.getCreatedBy() == null){
					revisionHistory.setCreatedBy(loginUser);
				}
				if (revisionHistory.getModifiedBy() == null){
					revisionHistory.setModifiedBy(loginUser);
				}
			}
		}
		if (entity instanceof ICheckModelNotNullInfo){
			ValidationUtil genericServiceUtil = getGenericServiceUtil();
			genericServiceUtil.checkNotNulllModel((ICheckModelNotNullInfo)entity);
		}
		if (entity instanceof ICheckModelDuplicateInfo){
			ValidationUtil genericServiceUtil = getGenericServiceUtil();
			genericServiceUtil.checkDuplicateModel((ICheckModelDuplicateInfo)entity);
		}
		
		if (entity instanceof PinyinAware){
			PinyinAware pinyinAware = (PinyinAware) entity;
			pinyinAware.setPinyin(ChineseSpeller.convert(pinyinAware.source(), false, false));
//			modified = true;
		}
		
		if (entity instanceof ProofNbrAware){
			ProofNbrAware aware = (ProofNbrAware) entity;
			String proofNbr = aware.getProofNbr();
			if (proofNbr == null){
				proofNbrRuleManager = getProofNbrRuleManager();
//				proofNbr =  proofNbrRuleManager.getNextNbr(aware ,null);
				aware.setProofNbr(proofNbr);
			}
		}
		
		if (entity instanceof EmployeeAware){
			EmployeeAware employeeAware = (EmployeeAware) entity;
			if (employeeAware.getDepartment() == null && employeeAware.getEmployee() != null){
				employeeAware.setDepartment(employeeAware.getEmployee().getDepartment());
			}
		}
		if (entity instanceof VersionAware){
			LoginUserService userService = getUserService();
			if (userService.getLoginUser() != null){
				VersionAware versionAware = (VersionAware) entity;
				versionAware.setCreated((User)userService.getLoginUser().getUserEx());
				versionAware.setCreatedOn(new Date());
			}
		}
		
		checkAcctAware(entity);
		
		return modified;
	}
	
	@Override
	public boolean onFlushDirty(Object entity, Serializable id,
			Object[] currentState, Object[] previousState,
			String[] propertyNames, Type[] types) {
		boolean modified = false;
		if (entity instanceof ICheckModelNotNullInfo){
			ValidationUtil genericServiceUtil = getGenericServiceUtil();
			genericServiceUtil.checkNotNulllModel((ICheckModelNotNullInfo)entity);
		}
		if (entity instanceof ICheckModelDuplicateInfo){
			ValidationUtil genericServiceUtil = getGenericServiceUtil();
			ICheckModelDuplicateInfo checkModel = (ICheckModelDuplicateInfo)entity;
			boolean checkDuplicate = false;
			
			String[] checkProperties = checkModel.gatherProperties();
			for(String property : checkProperties){
				for(int i = 0; i < propertyNames.length ; i++){
					if (property.equals(propertyNames[i])){
						Object previous = previousState[i];
						Object current = currentState[i];
						if (previous == null && current == null){
							
						} else {
							if (!(previous != null && previous.equals(current))){
								checkDuplicate = true;
							}
						}
						break;
					}
				}
				if (checkDuplicate) break;
			}
			
			if (checkDuplicate){
				genericServiceUtil.checkDuplicateModel(checkModel);
			}
		}
		
		if (entity instanceof PinyinAware){
			PinyinAware pinyinAware = (PinyinAware) entity;
			pinyinAware.setPinyin(ChineseSpeller.convert(pinyinAware.source(), false, false));
		}
		
		if (entity instanceof RevisionHistoryAware){
//				revisionHistory.setModifiedBy(loginUser);
//				revisionHistory.setModifyOn(new Date());
		}
		
		if (entity instanceof ProofNbrAware){
			ProofNbrAware aware = (ProofNbrAware) entity;
			String proofNbr = aware.getProofNbr();
			if (proofNbr == null){
				proofNbrRuleManager = getProofNbrRuleManager();
//				proofNbr =  proofNbrRuleManager.getNextNbr(aware ,null);
				aware.setProofNbr(proofNbr);
			}
		}
		
		if (entity instanceof EmployeeAware){
			EmployeeAware employeeAware = (EmployeeAware) entity;
			if (employeeAware.getDepartment() == null && employeeAware.getEmployee() != null){
				employeeAware.setDepartment(employeeAware.getEmployee().getDepartment());
			}
		}
		
		checkAcctAware(entity);
		
		return modified;
	}
	
	
	@Override
	public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
		checkAcctAware(entity);
	}
	
	protected ValidationUtil getGenericServiceUtil() {
		if (genericServiceUtil == null) {
			genericServiceUtil = ObjectFactory.getInstance().getBean(ValidationUtil.class, true);
		}
		return genericServiceUtil;
	}
	
	protected LoginUserService getUserService() {
		if (loginUserService == null) {
			loginUserService = ObjectFactory.getInstance().getBean(LoginUserService.class, true);
		}
		return loginUserService;
	}
	
	protected SystemLogService getSystemLogService(){
		if (systemLogService == null){
			systemLogService = ObjectFactory.getInstance().getBean(SystemLogService.class, true);
		}
		return systemLogService;
	}
	
	protected ProofNbrRuleManager getProofNbrRuleManager(){
		if (proofNbrRuleManager == null){
			proofNbrRuleManager = ObjectFactory.getInstance().getBean(ProofNbrRuleManager.class, true);
		}
		return proofNbrRuleManager;
	}
	
	private BeanIntrospector getIntrospector(){
		if (beanIntrospector == null){
			beanIntrospector = ObjectFactory.getInstance().getBean(BeanIntrospector.class, true);
		}
		return beanIntrospector;
	}

	private void checkAcctAware(Object entity){
		if (entity instanceof AcctTermCheckAware){
			AcctTerm acctTerm = getAcctTerm();
			if (acctTerm == null) return ;
			AcctTermCheckAware checkAware = (AcctTermCheckAware) entity;
			boolean check = checkAware.check(acctTerm);
			if (!check){
				throw new ApplicationException("不在当前会计期间,不能新增修改删除!", acctTerm.getName());
			}
		}
	}
	
	protected AcctTerm getAcctTerm(){
		return null;
	}
	
	/**
	 * Provide the entity name for the EntityMode.MAP 
	 */
	@Override
	public String getEntityName(Object object) {
		String entityName = ClassUtil.getClassName(object);
		return entityName;
	}
}
